package com.gzsxy.sso.core.config;


import com.gzsxy.sso.core.entity.Permission;
import com.gzsxy.sso.core.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.List;

/**
 * @author xiaolong
 * @version 1.0
 * @description: 拦截器 Security权限认证
 * @date 2021/11/10 16:32
 */
@Component
@EnableWebSecurity //开启WebSecurity模式
public class SecurityAutoConfig extends WebSecurityConfigurerAdapter {

    /**
     * 用户认证类
     */
    @Autowired
    private MemberDetailsService memberDetailsService;

    @Autowired
    private PermissionService permissionService;


    /**
     * 密码加密类
     */
    @Autowired
    private PasswordEncoder passwordEncoder;



    //认证白名单
    private static String AUTH_WHITELIST = ""
            + "/swagger**/**,/**/v2/api-docs,/v2/api-docs/**,/swagger-ui.html,/resources/**,/configuration**/**,/doc.html,/valid**,"
            +"/oauth/**,/admin/user/**,"
            +"/druid/**,"
            +"/webjars/**,/static/**,/lib/**,/**/*.js,/**/*.css,/favicon.ico,"
            +"/**/*.png,/**/*.jpg,/**/*.bmp,";

    /**
     * 认证  springboot 2.1.x可以直接使用
     * 密码编码：passwordEncoder
     * 在spring security 5.0+新增了很多的加密方法
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //memberDetailsService类是最先请求先去执行的，通过查询数据库获取账户信息去验证
        auth.userDetailsService(memberDetailsService).passwordEncoder(
                new PasswordEncoder() {

            //rawPassword输入的密码
            @Override
            public String encode(CharSequence rawPassword) {
                return (String)rawPassword;
            }


            //encodedPassword查询数据库里面已经经过md5加密后的密码
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
//                String rawPass = Base64Util.encryptToMD5((String) rawPassword);
                boolean result = rawPassword.equals(encodedPassword);
                return result;
            }
        });

    }


    /**
     * 授权
     * 链式编程
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        List<Permission> allPermission =
                permissionService.findAllPermission();

        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
                authorizeRequests = http.authorizeRequests();

        //添加所有权限
//        allPermission.forEach((p) ->{
//            //访问路径《======》访问的权限名
//            authorizeRequests.antMatchers(p.getUrl()).hasAnyAuthority(p.getPermTag());
//        });

//        //这些不需要认证就能访问
//        authorizeRequests.antMatchers(AUTH_WHITELIST.split("\\,")).permitAll()
//        //所有请求都需要通过认证
//        .anyRequest().authenticated();

        /*采用spring security 自带模式进行权限验证  */
        //表单提交给框架验证的路径
        http.formLogin().loginProcessingUrl("/Login").permitAll();
        //登录成功后跳转的url
        http.formLogin().successForwardUrl("/admin/user/login").permitAll();

        //防止网站攻击：get post --新版本已经融合了

        //关闭csrf功能,否则页面无法访问
        http.csrf().disable().cors();
    }



    /**
     * 解决AuthenticationManager类无法注入问题  密码模式
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 设置授权码模式的授权码如何 存取，这里采用数据库
     */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource){
        return new JdbcAuthorizationCodeServices(dataSource);
    }


    /**
     * 采用查询数据库方式获取客户端信息  clientDetailsServices Bean名字设置不同否则会覆盖 注入使用这个名字
     */
    @Bean("clientDetailsServices")
    public ClientDetailsService clientDetailsService(DataSource dataSource){
        JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService)clientDetailsService).setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

}
